package com.wtwd.campus.service.impl;

import com.alibaba.fastjson.JSON;
import com.wtwd.campus.common.Constants;
import com.wtwd.campus.common.RespCode;
import com.wtwd.campus.entity.SysUser;
import com.wtwd.campus.exception.BaseException;
import com.wtwd.campus.service.RedisService;
import com.wtwd.campus.utils.Tools;
import com.wtwd.campus.vcom.common.Constant;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author mjy
 * @date 2021/06/08
 * @description
 */
@Service
public class RedisServiceImpl implements RedisService {

    @Autowired
    private RedisTemplate redisTemplate;

    private static final Logger logger = LoggerFactory.getLogger(RedisServiceImpl.class);

    @Override
    public void createToken(SysUser sysUser, String token) {
        //以token为键，存储该用户key值(key值以前缀+账号名存取(账号名不能重复，保证key值的唯一性))默认过期时间30分钟
        String key = Constants.MANAGER_TOKEN_PREFIX + sysUser.getUserId();
        setKey(token, key, Constants.TOKEN_EXPIRE, TimeUnit.MINUTES);
        //以key为键,用户信息为value,存储用户信息
        HashMap<String, Object> userMap = new HashMap<>();
        userMap.put("current_token", token);//判断用户是否多端登录
        userMap.put("user", JSON.toJSONString(sysUser));
        setHash(key, userMap, Constants.TOKEN_EXPIRE, TimeUnit.MINUTES);
    }

    @Override
    public void setKey(String key, String value, long expireTime, TimeUnit timeUnit) {
        ValueOperations valueOperations = redisTemplate.opsForValue();
        if (expireTime == 0) {
            valueOperations.set(key, value);
        } else {
            valueOperations.set(key, value, expireTime, timeUnit);
        }
    }

    @Override
    public void setHash(String key, Map<String, Object> map, long expireTime, TimeUnit timeUnit) {
        redisTemplate.opsForHash().putAll(key, map);
        if (expireTime != 0) {
            redisTemplate.expire(key, expireTime, timeUnit);
        }
    }

    @Override
    public void setHash2(String key, Map<String, Object> map, long expireTime, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, map);
    }

    @Override
    public void setHash3(String key, Map<String, Object> map, long expireTime, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, map, expireTime, timeUnit);
    }

    @Override
    public Map<String, Object> getHash(String key) {
        return (Map<String, Object>) redisTemplate.opsForValue().get(key);
    }

    @Override
    public Map<String, Object> getUserInfoByToken(String token) {
        Map<String, Object> userInfo = null;
        try {
            // 通过token获取到用户对应的token
            String key = (String) redisTemplate.opsForValue().get(token);
            // 通过用户对应的key值，得到对应用户数据
            userInfo = redisTemplate.opsForHash().entries(key);
        } catch (RuntimeException e) {
            throw new BaseException(RespCode.TOKEN_UNAUTHORIZED);
        } finally {
            return userInfo;
        }

    }

    @Override
    public boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    @Override
    public List getValuesByLikePrefix(String prefix) {
        Set keys = redisTemplate.keys(prefix + "*");
        return redisTemplate.opsForValue().multiGet(keys);
    }

    @Override
    public String[] createCustomerToken(Integer customerId) {
        // 1、先查询是否有token，如果有，则清除
        if (redisTemplate.hasKey(Constants.CUSTOMER_TOKEN_PREFIX + customerId)) {
            Map<String, Object> tokenMsg = redisTemplate.opsForHash().entries(Constants.CUSTOMER_TOKEN_PREFIX + customerId);
            String accessToken = (String) tokenMsg.get("accessToken");
            redisTemplate.delete(accessToken);
        }
        //2.创建accessToken refreshToken
        String accessToken = Tools.getRamdomStr();
        String refreshToken = Tools.getRamdomStr();
        redisTemplate.opsForValue().set(accessToken, Constants.CUSTOMER_TOKEN_PREFIX + customerId, 2L, TimeUnit.HOURS);
        Map<String, Object> customerToken = new HashMap<>();
        customerToken.put("refreshToken", refreshToken);
        customerToken.put("accessToken", accessToken);
        redisTemplate.opsForHash().putAll(Constants.CUSTOMER_TOKEN_PREFIX + customerId, customerToken);
        redisTemplate.expire(Constants.CUSTOMER_TOKEN_PREFIX + customerId, 30L, TimeUnit.DAYS);
        return new String[]{accessToken, refreshToken};
    }


    @Override
    public String getValue(String key) {
        if (redisTemplate.hasKey(key)) {
            return (String) redisTemplate.opsForValue().get(key);
        }
        return null;
    }

    @Override
    public void deleteCommand(String imei, String index) {
        String key = Constants.COMMAND_PREFIX + imei;
        Object map = redisTemplate.opsForHash().entries(key);
        if (map != null) {
            logger.info("未删除指令前 redis map={}", map);
       /*     Map<String,Object> hashMap = (Map<String,Object>)map;
            logger.info("hashValue"+hashMap.get(index));
            hashMap.remove(index);
            redisTemplate.opsForHash().putAll(key, hashMap);*/
            logger.info("删除 redis指令 key={},index={} ", key, index);
            redisTemplate.opsForHash().delete(key, index);
            logger.info("删除指令后 redis map={}", redisTemplate.opsForHash().entries(key));
        }
    }

    @Override
    public void deleteHashByPrefix(String imei, String cmdPrefix) {
        ArrayList<String> delKeys = new ArrayList<>();
        String key = Constants.COMMAND_PREFIX + imei;
        Object map = redisTemplate.opsForHash().entries(key);
        if (map != null) {
            logger.info("未删除指令前 redis map={}", map);
            Map<String, Object> hashMap = (Map<String, Object>) map;
            Iterator<Map.Entry<String, Object>> iterator = hashMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Object> entry = iterator.next();
                if (entry.getKey().startsWith(cmdPrefix)) {
                    delKeys.add(entry.getKey());
                }
            }
            if (delKeys != null && delKeys.size() > 0) {
                for (String delKey : delKeys) {
                    redisTemplate.opsForHash().delete(key, delKey);
                }
            }
            logger.info("删除指令后 redis map={}", redisTemplate.opsForHash().entries(key));
        }

    }


    @Override
    public boolean verifyRefreshToken(Integer customerId, String refreshToken) {
        // 1、先查询是否有token，如果有，则清除
        if (!redisTemplate.hasKey(Constants.CUSTOMER_TOKEN_PREFIX + customerId)) {
            return false;
        }
        Map<String, Object> tokenMsg = redisTemplate.opsForHash().entries(Constants.CUSTOMER_TOKEN_PREFIX + customerId);
        String refresh = (String) tokenMsg.get("refreshToken");
        if (!refreshToken.equals(refresh)) {
            return false;
        }
        return true;
    }

    @Override
    public Integer customerToken2CustomerId(String accessToken) {
        Object o = redisTemplate.opsForValue().get(accessToken);
        if (o != null) {
            return Integer.parseInt(((String) o).split("_")[1]);
        }
        return null;
    }

    @Override
    public Map<String, Object> getCommandsByImei(String imei) {
        Object commandMap = redisTemplate.opsForHash().entries(Constants.COMMAND_PREFIX + imei);
        if (commandMap != null) {
            return (Map<String, Object>) commandMap;
        }
        return null;
    }

    @Override
    public boolean deleteKey(String key) {
        return redisTemplate.delete(key);
    }

    @Override
    public Map<String, Object> getHashMap(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    @Override
    public void setUnInStorageDevice(String imei) {
        Map<String, Object> entries = redisTemplate.opsForHash().entries(Constants.UN_STORAGE_DEVICE);
        if (entries == null) {
            entries = new HashMap<>();
        }
        entries.put(imei, "0");
        redisTemplate.opsForHash().putAll(Constants.UN_STORAGE_DEVICE, entries);
    }

    @Override
    public void deleteUnInStorageList(List<String> list) {
        BoundHashOperations bound = redisTemplate.boundHashOps(Constants.UN_STORAGE_DEVICE);
        Map<String, Object> entries = bound.entries();
        if (entries != null) {
            for (String s : list) {
                bound.delete(Constants.UN_STORAGE_DEVICE, s);
            }
        }
    }

    @Override
    public Set keys(String pattern) {
        Set keys = redisTemplate.keys(pattern);
        return keys;
    }

    @Override
    public String createVcomTypeToken(Integer vcomTypeCustomerId) {
        String token = Tools.getRamdomStr();
        Map<String, Object> map = new HashMap<>();
        map.put("customerId", String.valueOf(vcomTypeCustomerId));
        map.put("accessToken", token);
        redisTemplate.opsForHash().putAll(Constant.VCOM_TYPE_TOKEN_PREFIX + vcomTypeCustomerId, map);
        redisTemplate.opsForValue().set(token, Constant.VCOM_TYPE_TOKEN_PREFIX + vcomTypeCustomerId, 24l, TimeUnit.HOURS);
        redisTemplate.expire(Constant.VCOM_TYPE_TOKEN_PREFIX + vcomTypeCustomerId, 24L, TimeUnit.HOURS);
        return token;
    }

    @Override
    public long getCommandNumberByImei(String imei) {
        Long increment = redisTemplate.opsForValue().increment(Constant.COMMAND_PREFIX + imei, 1);
        if (increment == null) {
            return 0;
        }
        return increment;
    }

    @Override
    public String getRequestIdByVcomTypeCustomerId(int vcomTypeCustomerId) {
        String requestId = (String) redisTemplate.opsForValue().get(Constant.REQUESTID_PREFIX + vcomTypeCustomerId);
        if (StringUtils.isBlank(requestId)) {
            requestId = "000000";
        }
        return requestId;
    }

    @Override
    public Map<String, Object> getVcomUserInfo(String token) {
        // 通过token获取到用户对应的token
        String key = (String) redisTemplate.opsForValue().get(token);
        // 通过用户对应的key值，得到对应用户数据
        return redisTemplate.opsForHash().entries(key);
    }

    @Override
    public Set<String> getKeysByLikePrefix(String cmdPrefix) {
        return redisTemplate.keys(cmdPrefix + "*");
    }

    @Override
    public boolean lock(String key, String value, long expireTime) {
        redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
        return redisTemplate.opsForValue().setIfAbsent(key, value);
    }

    @Override
    public boolean unlock(String key, String value) {
        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
            return false;
        }
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript();
        //用于解锁的lua脚本位置
        redisScript.setScriptText(
                "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                        "return redis.call('del', KEYS[1]) " +
                        "else " +
                        "return 0 " +
                        "end");
        redisScript.setResultType(Long.class);
        Object result = redisTemplate.execute(redisScript, Collections.singletonList(key), value);
        return result.equals(Long.valueOf(1));
    }

}
